#!/usr/bin/env python
# encoding: utf-8
"""
QueryManager.py

"""

import re
import math

import DataManager

class Query(object):

    def __init__(self, indexName, query):
        """ 
        Query:
        handler for queries to an inverted index.
        Limited query-parser functionality
        """
        self.corpus = indexName
        data = DataManager.Corpus(self.corpus)
        data.open()
        self.index = data.get('Index')
        self.lexicon = data.get('Lexicon')
        
        self.query = query
        self.tokens = self.query.split()
        t = len(self.tokens)
        if t > 3:
            raise IOError('Query too long!')
        elif t == 1:
            self.result = self.termQuery()
        elif t == 3 and '~' in self.tokens[1]:
            self.result = self.proximityQuery()
        elif t == 3:
            self.result = self.phraseQuery()
        else:
            self.result = 'Unknown error: Query could not be processed!'
    
    def sortQueryTokens(self):
        """ sort tokens by frequency """
        pass
    
    def termQuery(self):
        """
        Example query: Haus
        """
        if self.lexicon.has_key(self.tokens[0]):
            return self.query + str(self.index[self.tokens[0]])
        else:
            return 'No Results for your query: %s' % (self.query)
    
    def phraseQuery(self):
        """ 
        Query: "das gelbe Haus" 
        """
        # TODO: finish implemantation 
        p1 = self.index[self.tokens[0]].items()
        p2 = self.index[t[1]].items()
        return self.positionalIntersect(p1, p2, 1)
    
    def proximityQuery(self):
        """
        Query: 'Alex kaufen'~3  (Lucene style)
        Query: 'Alex ~3 kaufen'
        Query: VVFIN ~0 buchen , both have same position
        """
        # TODO check lexicon first
        op = self.tokens[1][1]
        if len(self.index[self.tokens[0]].items()) < len(self.index[self.tokens[2]].items()):
            p1 = self.index[self.tokens[0]].items()
            p2 = self.index[self.tokens[2]].items()
        else:
            p1 = self.index[self.tokens[2]].items()
            p2 = self.index[self.tokens[0]].items()
        return self.positionalIntersect(p1, p2, int(op))
    
    def positionalIntersect(self, p1, p2, k):
        """
        merging two positional postings:
        Input:
            - p1, p2 are tuples of tuples: (docID, (#,[positions]))
            - k is the desired offset
        Output:
            List of tuples with (docID, (pos))
        """
        result = []
        while len(p1) != 0 and len(p2) != 0:
            if p1[0][0] == p2[0][0]:
                l = []
                if len(p1[0][1][1]) < len(p2[0][1][1]):
                    pp1 = p1[0][1][1]
                    pp2 = p2[0][1][1]
                else:
                    pp1 = p2[0][1][1]
                    pp2 = p1[0][1][1]
                while len(pp1) != 0 and len(pp2) != 0:
                    if math.fabs(pp1[0] - pp2[0]) <= k:
                        l.append(pp2[0])
                    elif pp2[0] > pp1[0]:
                        break
                    pp2.pop(0)
                    while len(l) != 0 and math.fabs(l[0]-pp1[0]) > k:
                        l.pop(0)
                    for ps in l:
                        result.append((p1[0][0], pp1[0], ps))
                        pp1.pop(0)
                p1.pop(0)
                p2.pop(0)
            elif p1[0] < p2[0]:
                p1.pop(0)
            else:
                p2.pop(0)
        return result
    
    def __str__(self):
        return "Corpus: %s, Query: %s" % (self.corpus, self.query)
    
if __name__ == '__main__':
	
	print 'QueryManager'
